#include "myudpserver.h"

int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
    iconv_t cd;
    int rc;
    char **pin = &inbuf;
    char **pout = &outbuf;

    cd = iconv_open(to_charset,from_charset);
    if (cd==0) return -1;
    memset(outbuf,0,outlen);
    if (iconv(cd,pin,(size_t*)&inlen,pout,(size_t*)&outlen)==-1) return -1;
    iconv_close(cd);
    return 0;
}

int gb2312_to_utf8(char *inbuf,int inlen,char *outbuf,int outlen)
{
    return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}

std::string url_encode(const std::string& encode_url)
{
	std::string src = encode_url;
	char hex[] = "0123456789ABCDEF";
	string dst;
 
	for (size_t i = 0; i < src.size(); ++i)
	{
		unsigned char cc = src[i];
		if (isascii(cc))
		{
			if (cc == ' ')
			{
				dst += "%20";
			}
			else if(cc =='\r')
			{
				dst+="%0D";
			}
			else if(cc =='\n')
			{
				dst+="%0A";
			}
			else
				dst += cc;
		}
		else
		{
			unsigned char c = static_cast<unsigned char>(src[i]);
			dst += '%';
			dst += hex[c / 16];
			dst += hex[c % 16];
		}
	}
	return dst;
}

MyUdpServer::MyUdpServer()
{
    s_exit_flag = 0;
    s_show_headers = 0;
    map_filename.clear();
    Config::instance();
}

MyUdpServer::~MyUdpServer()
{

}

void MyUdpServer::on_udp_msg(char* buf, int len, char* dst_ip)
{
    s_exit_flag = 0;
    http_res_data.clear();
    if(len > 0) {
        //只取其中8位
        long cmd = buf[2]&0x000000ff;
        if(cmd == 0xfa) {   //获取录播主机状态
            get_record_state(buf,len,dst_ip);                    
        }
        else if(cmd == 0xfb) { //控制录播主机            
            int ctrl = buf[4]&0x000000ff; //录播指令
            if(ctrl == 0x01) { //开始录制
                start_record(buf,len,dst_ip);                              
            }
            else if(ctrl == 0x03) { //停止录制
                stop_record(buf,len,dst_ip);                
            }
            else {
                hi_warn("invalid record proc cmd: %d", ctrl);
            }
        }
        else {
            hi_warn("invlid cmd: 0x%02x", buf[2]);
        }      
    }
}

void MyUdpServer::get_record_state(char *buf, int len,char* dst_ip) 
{   
    string ip;
    stringstream send_cmd;
    char str_response[512] = {0};
    ip.clear();    //清空ip地址
    send_cmd.clear();
    for(int i = 9 ; i < len-6 ; i++) {
        ip += buf[i];
    }
    printf("ip :%s\n",ip.c_str());
    unsigned int unique_code = 0;
    string url = "";
    int ret = Config::instance()->get_url(ip.c_str(), unique_code, url);
    int response_len = ip.size()+17;
    if(ret < 0) {
        hi_error("not find device url ip=%s", ip.c_str());
        str_response[0] = (response_len/255);
        str_response[1] = (response_len%255);
        str_response[2] = 0xfa;   //录播控制指令
        str_response[3] = 0x02;   //回复标志
        str_response[4] = ERR_NOT_CFG_URL;
        str_response[5] = 0x01;   //停止录播状态
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        return ;             
    }
    
    send_cmd << "http://127.0.0.1:8082/record/record.action?action=3";
    send_cmd << "&uniqueCode="<<unique_code;                    
    send_cmd << "&flowUrl="<<url;    

    hi_trace("send http cmd: %s to video nolinear", send_cmd.str().c_str());
    //http指令
    mg_mgr_init(&mgr, NULL);
    string http_url = url_encode(send_cmd.str()); 
    mg_connect_http(&mgr, ev_handler, http_url.c_str(), NULL, NULL); //请求http
    while (s_exit_flag == 0) {
        mg_mgr_poll(&mgr, 1000);
    }
    mg_mgr_free(&mgr);
    
    str_response[0] = (response_len/255);
    str_response[1] = (response_len%255);
    str_response[2] = 0xfa;
    str_response[3] = 0x02;

    if(http_res_data.size() > 0) {
        hi_trace("svr res: %s", http_res_data.c_str());
        Json json_str = Json::fromJson(http_res_data);
        if(json_str["code"].asInt() == 200) {
            str_response[4] = ERR_NO;
            if(json_str["isOnLine"].asInt() == 1 || json_str["isOnLine"].asInt() == 3){
                str_response[5] = 0x01;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);
            }           
            else if(json_str["isOnLine"].asInt() == 2) {
                str_response[5] = 0x02;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);
            }
            UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
            return;
        }
        else {
            str_response[4] = ERR_NO_RECORD_SVR;
            str_response[5] = 0x01;
            memcpy(str_response+6,"<COL>",5);
            memcpy(str_response+11,ip.c_str(),ip.size());
            memcpy(str_response+11+ip.size(),"</COL>",6);
            UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
            hi_warn("video nolinear server  no response!");
            return;
        }
    } 
    else {
        //http没有回复消息
        str_response[4] = ERR_NO_RECORD_SVR;
        str_response[5] = 0x01;
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        hi_warn("video nolinear server  no response!");
    }
    return;
}

void MyUdpServer::start_record(char* buf, int len ,char* dst_ip)
{
    string ip="";
    string filename = "";  
    stringstream send_cmd;
    char str_response[512] = {0};
    send_cmd.clear();
    
    //解析ip   
    int j = 0;  //用于保存IP地址解析的最后位置，方便解析后面的文件名         
    for(int i = 10 ; i < 29 ; i++) {
        if(buf[i+1] == '/') {
            j = i;
            break;
        }
        ip += buf[i];
    }
    printf("ip :%s\n",ip.c_str());

    //查找用户url,返回url在配置文件中的位置
    unsigned int unique_code = 0;
    string url = "";
    int ret = Config::instance()->get_url(ip.c_str(),unique_code,url);
    int response_len = ip.size()+17;
    if(ret < 0) {
        hi_warn("please config rtmp url for %s", ip.c_str());
        //返回用户未得到url数据的信息
        str_response[0] = (response_len/255);
        str_response[1] = (response_len%255);
        str_response[2] = 0xfb;   //录播控制指令
        str_response[3] = 0x02;   //回复标志
        str_response[4] = ERR_NOT_CFG_URL;
        str_response[5] = 0x01;   //停止录播状态
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        return;
    }
    
    //解析录制文件名
    for(int i = j+11 ; i < len-6 ; i++) {
        if(buf[i+1] == '/') {
            break;
        }        
        filename += buf[i];
    }
    map_filename.insert(pair<unsigned int,string>(unique_code,filename)); 
    hi_error("file_name start:%s\n",filename.c_str());
    //转码
    char out[512];
    gb2312_to_utf8((char*)filename.c_str(), filename.size(), out, 512);
    
    string out_name(out);
    int pos = out_name.find("(");
    if(pos != string::npos) 
    {
        out_name.insert(pos, "\\");
    }        

    pos = out_name.find(")");
    if(pos != string::npos) 
    {
        out_name.insert(pos, "\\");
    }        

    printf("out_name start:%s\n",out_name.c_str());
    //发送录制请求到非编服务            
    send_cmd << "http://127.0.0.1:8082/record/record.action?";
    send_cmd << "action=1";
    send_cmd << "&uniqueCode="<<unique_code;        
    send_cmd << "&user=test&flowUrl="<<url;
    //send_cmd << "&user=test&flowUrl="<<"rtmp://47.110.43.212/live/neimeng";
    send_cmd << "&path=/mnt/vod/"<<out_name;    
    send_cmd << "&callbackurl="<<"tmp";      
    send_cmd << "&otherParam=tmp";
   
    hi_trace("send http cmd: %s to video nolinear", send_cmd.str().c_str());
    
    mg_mgr_init(&mgr, NULL);
    string http_url = url_encode(send_cmd.str()); 
    mg_connect_http(&mgr, ev_handler, http_url.c_str(), NULL, NULL);  
    while (s_exit_flag == 0) {
        mg_mgr_poll(&mgr, 1000);
    }      
    mg_mgr_free(&mgr);
    str_response[0] = ((response_len)/255);
    str_response[1] = ((response_len)%255);
    str_response[2] = 0xfb;
    str_response[3] = 0x02;

    if(http_res_data.size() > 0) {    
        Json json_str = Json::fromJson(http_res_data);
        str_response[4] = ERR_NO;        
        if(json_str["code"].asInt() == 200) {
            if(json_str["isOnLine"].asInt() == 1 || json_str["isOnLine"].asInt() == 3){ 
                string url_mp4 = "";
                url_mp4 += "http://47.110.43.212/vod/";
                url_mp4 += filename; 
                response_len += (11 + url_mp4.size());          
                str_response[0] = ((response_len)/255);
                str_response[1] = ((response_len)%255);
                str_response[5] = 0x01;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);   
                memcpy(str_response+17+ip.size(),"<COL>",5);
                memcpy(str_response+22+ip.size(),url_mp4.c_str(),url_mp4.size());
                memcpy(str_response+22+ip.size()+url_mp4.size(),"</COL>",6);
                UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
                return;
            }
            else if(json_str["isOnLine"].asInt() == 2) {
                str_response[0] = ((response_len)/255);
                str_response[1] = ((response_len)%255);  
                str_response[5] = 0x02;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);   
                UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
 
                return;
            } 
        }
        else {
            str_response[4] = ERR_NO_RECORD_SVR;
            str_response[5] = 0x01;
            memcpy(str_response+6,"<COL>",5);
            memcpy(str_response+11,ip.c_str(),ip.size());
            memcpy(str_response+11+ip.size(),"</COL>",6);
            UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
            hi_warn("video nolinear server  no response!");
      
            return;
        }
    }
    else {
        //http没有回复消息
        str_response[4] = ERR_NO_RECORD_SVR;
        str_response[5] = 0x01;
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        hi_warn("video nolinear server  no response!");
    }
    return;
}

void MyUdpServer::stop_record(char* buf, int len,char* dst_ip) 
{    
    string ip = "";
    string filename = "";
    stringstream send_cmd;
    char str_response[512] = {0};
    unsigned int unique_code = 0;
    string url = "";
    send_cmd.clear();

    //解析ip
    ip.clear();    
    int j = 0;
    for(int i = 10 ; i < 29 ; i++) {
        if(buf[i+1] == '/') {
            j = i;
            break;
        }
        ip += buf[i];
    }
    
    printf("ip :%s\n",ip.c_str());

    //查找url
    int ret = Config::instance()->get_url(ip.c_str(),unique_code,url); 
    int response_len = ip.size()+17;
    if(ret < 0) {
        hi_warn("please config rtmp url for %s", ip.c_str());
        str_response[0] = (response_len/255);
        str_response[1] = (response_len%255);
        str_response[2] = 0xfb;   //录播控制指令
        str_response[3] = 0x02;   //回复标志
        str_response[4] = ERR_NOT_CFG_URL;  
        str_response[5] = 0x01;   //停止录播状态
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);   
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        return;
    }

    auto it = map_filename.find(unique_code);
    if(it == map_filename.end()) {
        hi_warn("map has no name filename");
        return;
    }
    else {
        pair<unsigned int ,string> pair_filename = *it;
        filename = pair_filename.second;
    }
    hi_error("filename stop:%s",filename.c_str());
           
    send_cmd << "http://127.0.0.1:8082/record/record.action?action=2";
    send_cmd << "&uniqueCode=" << unique_code;    
    hi_trace("send request %s", send_cmd.str().c_str());  

    s_exit_flag = 0;
    http_res_data.clear();
    mg_mgr_init(&mgr, NULL);
    string http_url = url_encode(send_cmd.str()); 
    mg_connect_http(&mgr, ev_handler, http_url.c_str(), NULL, NULL);  //控制停止录播
    while (s_exit_flag == 0) {
        mg_mgr_poll(&mgr, 1000);
    }      
    mg_mgr_free(&mgr);
    
    str_response[0] = ((response_len)/255);
    str_response[1] = ((response_len)%255);
    str_response[2] = 0xfb;
    str_response[3] = 0x02;   

    if(http_res_data.size() > 0) {
        //hi_trace("recv video nolinea msg: %s", http_res_data.c_str());
        Json json_str = Json::fromJson(http_res_data);
        if(json_str["code"].asInt() == 200) {
            str_response[4] = ERR_NO;
            if(json_str["isOnLine"].asInt() == 1 || json_str["isOnLine"].asInt() == 3){
                string url_mp4 = "";
                url_mp4 += "http://47.110.43.212/vod/";
                url_mp4 += filename; 
                response_len += (11 + url_mp4.size());
                str_response[0] = ((response_len)/255);
                str_response[1] = ((response_len)%255);
                str_response[5] = 0x01;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);   
                memcpy(str_response+17+ip.size(),"<COL>",5);
                memcpy(str_response+22+ip.size(),url_mp4.c_str(),url_mp4.size());
                memcpy(str_response+22+ip.size()+url_mp4.size(),"</COL>",6);
                UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);

                char out[255];
                gb2312_to_utf8((char*)filename.c_str(), filename.size(), out, 255);
    
                string out_name(out);
                int pos = out_name.find("(");
                if(pos != string::npos) {
                    out_name.insert(pos, "\\");
                }        
                pos = out_name.find(")");
                if(pos != string::npos) {
                    out_name.insert(pos, "\\");
                }        

                filename = out_name;
                pos = out_name.find(".");
                if(pos != string::npos) {
                    out_name = out_name.erase(pos,4);
                }        

                //sleep 时间 要等录像文件停止需要时间
                // for(int i = 0 ; i < 5 ; i++) {
                //     stringstream save_image;
                //     save_image << "./ffmpeg -i ";
                //     save_image << "/mnt/vod/";
                //     save_image << filename;
                //     save_image << " -y -f image2 -t 3 ";
                //     save_image <<"/mnt/vod/"<<out_name;
                //     save_image << "_jpg";
                //     save_image << (i+1);
                //     save_image << ".jpg";
                //     system(save_image.str().c_str());     //执行ffmpeg保存指令
                //     hi_trace("ffmpeg snatshop cmd %s",save_image.str().c_str());
                // }
                // return;
            }
            else if(json_str["isOnLine"].asInt() == 2) {
                str_response[5] = 0x02;
                memcpy(str_response+6,"<COL>",5);
                memcpy(str_response+11,ip.c_str(),ip.size());
                memcpy(str_response+11+ip.size(),"</COL>",6);  
                UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
                return;
            } 
        }
        else {
            str_response[4] = ERR_NO_RECORD_SVR;
            str_response[5] = 0x01;
            memcpy(str_response+6,"<COL>",5);
            memcpy(str_response+11,ip.c_str(),ip.size());
            memcpy(str_response+11+ip.size(),"</COL>",6);  
            UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
            hi_warn("video nolinear server  no response!");
            return;
        }
    }
    else {
        //http没有回复消息
        str_response[4] = ERR_NO_RECORD_SVR;
        str_response[5] = 0x01;
        memcpy(str_response+6,"<COL>",5);
        memcpy(str_response+11,ip.c_str(),ip.size());
        memcpy(str_response+11+ip.size(),"</COL>",6);  
        UdpClient::send_data_onece(str_response,response_len,UDPPORT,dst_ip);
        hi_warn("video nolinear server  no response!");
    }
    
    return;
}

void MyUdpServer::ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
  struct http_message *hm = (struct http_message *) ev_data;

  switch (ev) {
  case MG_EV_RECV:
      break;
  case MG_EV_CONNECT:
      if (*(int *) ev_data != 0) {
          s_exit_flag = 1;
      }
      break;
  case MG_EV_HTTP_REPLY:
      nc->flags |= MG_F_SEND_AND_CLOSE;
      http_res_data.clear();      
      http_res_data = string(hm->body.p, hm->body.len);  //去除多余的字符，防止json解码出问题
      putchar('\n');
      s_exit_flag = 1;
      break;
  case MG_EV_CLOSE:
      if (s_exit_flag == 0) {
          printf("Server closed connection\n");
          s_exit_flag = 1;
      }
      break;
  default:
      break;
  }
}
